package mainPackage;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

import parser.FunctionSyntacticException;
import parser.ParserConsulta;
import parser.consulta.Consulta;
import parser.consulta.ConsultaCompuesta;
import parser.simbolo.delimitador.Delimitador;
import parser.simbolo.delimitador.Parentesis1;
import parser.simbolo.delimitador.Parentesis2;
import parser.simbolo.operador.And;
import parser.simbolo.operador.Not;
import parser.simbolo.operador.Operador;
import parser.simbolo.operador.Or;

import structuresManagers.BplusTreeManager;
import structuresManagers.SignatureManager;
import FilesManagers.CantOpenFileException;
import Filters.FullFilter;


public class ClasePrincipal {

	@SuppressWarnings("deprecation")
	private static String arbolFile ="arbol.txt";
	private static String signatureFile ="firmas.txt";
	public static void main(String args[]){
	
		try {	
			
			FullFilter filtro = new FullFilter("./conf/stopwords.conf","./conf/stemming.conf","./conf/badcharacters.txt");
			//IndexManager indexManager = new IndexManager("urls.txt",filtro);
			BplusTreeManager indexManager = new BplusTreeManager("urls.txt","urlIndexadas.txt",filtro);
			SignatureManager signatureManager = new SignatureManager("urls.txt","urlFirmadas.txt",filtro);
			
			/* inicializacion de las consultas booleanas */
			Consulta c;
			
			List<Operador> listaOperandos = new ArrayList<Operador>();
			listaOperandos.add(new Or());
			listaOperandos.add(new And());
			listaOperandos.add(new Not());
			
			List<Delimitador> listaDelimitadores = new ArrayList<Delimitador>();
			listaDelimitadores.add(new Parentesis1());
			listaDelimitadores.add(new Parentesis2());	
			
			
			
			/* inicializacion de las consultas booleanas */
			
			
			//SignatureFileManager signatureFileManager = new SignatureFileManager("urls.txt",filtro);
			SignatureManager signatureFileManager = new SignatureManager("urls.txt","urlfirmadas.txt",filtro);
			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	        while(true){
	        	System.out.println("****************************************");
	        	System.out.println("Tp1 - Primera Entrega - Grupo Bob Nervio");
		        System.out.println("****************************************");
		        System.out.println();
		        System.out.println("A - Crear un nuevo indice");
		        System.out.println("B - Agregar nuevas urls al indice existente");
		        System.out.println("C - Buscar Palabra en indice");
		        System.out.println("D - Listar todos los registros secuencialmente");
		        System.out.println("E - Crear un nuevo Archivo de Firmas");
		        System.out.println("F - Buscar Palabra en Archivo de firmas");
		        System.out.println("Q - Salir");
		        System.out.println();
		        System.out.print("Opcion : ");
	        
			
		        System.gc();
		       // indexManager.setLogger(false); //no Va creando un archivo con las palabras que le paso al arbol
		        
		        Cronometro cronometro = new Cronometro();
			
				
				String opcion = in.readLine( );
				if((opcion.trim().equals("A"))||(opcion.trim().equals("a"))){			
					
					while(true){
						System.out.println("Ingrese el tamaño del nodo deseado expresado en bytes");
						System.out.println("NOTA: debe ser potencia de 2 y mayor o igual a 128");
						System.out.println();
				        System.out.print("Opcion : ");
				        
				        opcion = in.readLine( );
				        if (isValidNodeSize(opcion)){
					    	break;	
				        }
				        System.out.println("TAMAÑO INCORRECTO, ingrese nuevamente");
				        
					}										
					
					System.out.println("Start: " + cronometro.iniciar());					
					//La paso el nombre del indice para que en caso de ser necesario, podamos generar varios indices, o mismo para realizar pruebas.
					//Si quiero crear el indice----, borrar el archivo del arbol y el de las urls indexadas.
					indexManager.makeNewIndex(arbolFile,Integer.valueOf(opcion));
					System.out.println("End: " + cronometro.finalizar());
					System.out.println("Time: " + cronometro.duracion());
					
					
				}else if((opcion.trim().equals("B"))||(opcion.trim().equals("b"))){
					if(!arbolExiste()){
						System.out.println("No existe ningún índice, por favor cree uno primero");
						continue;
					}
					
					System.out.println("El indexado se inicio en: "+cronometro.iniciar());
					//Si quiero continuar con un indice ya creado anteiormente
					indexManager.makeIndex(arbolFile,128); //el nodeSize es dummy, lo lee del archivo
					System.out.println("El indexado termino en: "+cronometro.finalizar());
					System.out.println("El indexado se hizo en: "+cronometro.duracion());
					
					
				}else if((opcion.trim().equals("C"))||(opcion.trim().equals("c"))){
					if(!arbolExiste()){
						System.out.println("No existe ningún índice, por favor cree uno primero");
						continue;
					}
					System.out.println();
			        System.out.print("Palabra a buscar : ");
			        String palabrasBuscadas= in.readLine( );
			        //Si quiero hacer la consulta --
			        //String [] palabrasBuscadas={"iphoNe","feria","unla","seremos","manuelitaviviaen","diario","soldering","limite","burning","kpsec","comisario","RamBo"};
			        //for(int j=0; j<palabrasBuscadas.length;j++){
						
			        
			        
			        String buscada = palabrasBuscadas;//filtro.procesarSearch(palabrasBuscadas/*[j]*/);
						//System.out.print("Palabra a buscar : " + buscada);
					       
						if(!buscada.trim().equals("")){
							//String res[]= indexManager.searchIndex(arbolFile,buscada);						
							
							try{
								ParserConsulta.validarConsulta(palabrasBuscadas,listaOperandos,listaDelimitadores);
								c = new ConsultaCompuesta("temp/",indexManager,arbolFile);
								c.setStringConsulta(palabrasBuscadas);
								c.ejecutar();
								//System.out.println();
							}catch(FunctionSyntacticException e){
								System.out.println(palabrasBuscadas+" -> "+e.getMessage());
								continue;
							}
							
							String res[]=c.getResultado();
							
							System.out.println("ENCONTRADO EN:");							
							if(res!=null){
								for(int i=0; i<res.length;i++){
									System.out.println(res[i]);
									
								}
								System.out.println("************************");
							}else{
								System.out.println("Ningun resultado exitoso");
							}
						}else{
							
							System.out.println("La palabra "+palabrasBuscadas/*[j]*/+" es muy general y fue limpiada por los filtros, intente de nuevo");
						}
					//}
				}else if((opcion.trim().equals("D"))||(opcion.trim().equals("d"))){
					if(!arbolExiste()){
						System.out.println("No existe ningún índice, por favor cree uno primero");
						continue;
					}					
					
					System.out.println("El listado se inicio en: "+cronometro.iniciar());
					indexManager.listIndex(arbolFile);
					System.out.println("El listado finalizó en: "+cronometro.finalizar());
					System.out.println("El listado demoro en total : "+cronometro.duracion());
					System.out.println("La salida se encuentra en: list.txt");
					
				}else if((opcion.trim().equals("E"))||(opcion.trim().equals("e"))){			
					
					while(true){
						System.out.println("Ingrese el tamaño en bits del hash deseado expresado en bytes");
						System.out.println("NOTA: debe ser potencia de 2 y mayor o igual a 128");
						System.out.println();
				        System.out.print("Opcion : ");
				        
				        opcion = in.readLine( );
				        if (isValidNodeSize(opcion)){
					    	break;	
				        }
				        System.out.println("TAMAÑO INCORRECTO, ingrese nuevamente");
				        
					}
					String cantHash;
					while(true){
						System.out.print("Cantidad de Funciones de Hash a usar (1 a 7):");
						cantHash = in.readLine( );
				        if (cantHash.equals("1")
				        	|| cantHash.equals("2")
				        	|| cantHash.equals("3")
				        	|| cantHash.equals("4")
				        	|| cantHash.equals("5")
				        	|| cantHash.equals("6")
				        	|| cantHash.equals("7")){
					    	break;	
				        }
				        System.out.println("INCORRECTO, ingrese nuevamente");
				        
					}
					
					System.out.println("Start: " +cronometro.iniciar());
					signatureFileManager.makeNewSignature(signatureFile,Integer.valueOf(opcion),Integer.valueOf(cantHash));
					
					System.out.println("End: " +cronometro.finalizar());
					System.out.println("Time: " +cronometro.duracion());
					


					
				}else if((opcion.trim().equals("F"))||(opcion.trim().equals("f"))){
					if(!signatureFileExiste()){
						System.out.println("No existe ningún archivo de firmas, por favor cree uno primero");
						continue;
					}
					System.out.println();
			        System.out.print("Palabra a buscar : ");
			        String palabrasBuscadas= in.readLine( );
			        //Si quiero hacer la consulta --
			        //String [] palabrasBuscadas={"iphoNe","feria","unla","seremos","manuelitaviviaen","diario","soldering","limite","burning","kpsec","comisario","RamBo"};
			        //for(int j=0; j<palabrasBuscadas.length;j++){
					//	String buscada = filtro.procesarSearch(palabrasBuscadas/*[j]*/);
						if(!palabrasBuscadas.trim().equals("")){
							
							//String res[]=signatureManager.search(signatureFile,palabrasBuscadas);
							
							try{
								ParserConsulta.validarConsulta(palabrasBuscadas,listaOperandos,listaDelimitadores);
								c = new ConsultaCompuesta("temp/",signatureManager,signatureFile);
								c.setStringConsulta(palabrasBuscadas);
								c.ejecutar();
								//System.out.println();
							}catch(FunctionSyntacticException e){
								System.out.println(palabrasBuscadas+" -> "+e.getMessage());
								continue;
							}
							String res[]=c.getResultado();
							
							
							System.out.println("ENCONTRADO EN:");
							if(res!=null){
								for(int i=0; i<res.length;i++){
									System.out.println(res[i]);
									
								}
								System.out.println("************************");
							}else{
								System.out.println("Ningun resultado exitoso");
							}
						}else{
							
							System.out.println("La palabra "+palabrasBuscadas/*[j]*/+" es muy general y fue limpiada por los filtros, intente de nuevo");
						}
					//}
				}else if((opcion.trim().equals("Q"))||(opcion.trim().equals("q"))){
					break;
				}else {
					System.out.println("Opcion incorrecta!");
				}
	
				
			
	        }
		} catch (CantOpenFileException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.err.println(e.getMessage());
		} catch (IOException e) {
			// TODO Bloque catch generado automáticamente
			e.printStackTrace();
		}
		
		
	}

	private static boolean arbolExiste() {
		try {
			RandomAccessFile file = new RandomAccessFile(arbolFile,"r");
			file.close();
		} catch (FileNotFoundException e) {
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}

	private static boolean signatureFileExiste() {
		try {
			RandomAccessFile file = new RandomAccessFile(signatureFile,"r");
			file.close();
		} catch (FileNotFoundException e) {
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}

	private static boolean isValidNodeSize(Integer integer) {
		if(integer>=128){
			if(Math.floor((Math.log(integer) / Math.log(2)))==(Math.log(integer) / Math.log(2))){
				return true;
			}
		}
		return false;
	}
	private static boolean isValidNodeSize(String s) {
		try{
			
			return isValidNodeSize(Integer.valueOf(s));
		}catch(NumberFormatException e){
			return false;
			
		}
	}
	
	
}
